<?php
class Tests {
  
  static $instance;
  private $arTests;
  private $arReflectionClasses;
  
  function findAllImplementedTests($dir) {
    $this->arTests = array();
    foreach (self::getTestClassNames($dir) as $testClassName) {
      $class = new ReflectionClass($testClassName);
      $this->arTests[$testClassName] = self::getTestNames($class);
      $this->arReflectionClasses[$testClassName] = $class;
    }
    return $this->arTests;
  }
  
  /**
   * @return ReflectionClass
   */
  function getReflectionClass($testClassName) {
    return $this->arReflectionClasses[$testClassName];
  }
  
  function hasTest($class, $name) {
    $res = array_key_exists($class,$this->arTests) && in_array($name,$this->arTests[$class]);
    return $res;
  }
  
  /**
   * Static - used to verify if a test exists.
   *
   * @todo optimize to load only the needed info 
   * @param string $class the complete name of the class
   * @param string $name the complete name of the method
   */
  static function testExists( $dir, $class, $name ) {
    if(!self::$instance) {
      self::$instance = new Tests;
      self::$instance->findAllImplementedTests($dir);
    }
    return self::$instance->hasTest( $class, $name );
  }
  
  static function getTestNames(ReflectionClass $class) {
    $arTestNames = array();
    foreach($class->getMethods() as $method) {
      $name = $method->getName();
      if(substr($name,0,4) == 'test') {
        $arTestNames[] = $name;
      }
    }
    return $arTestNames;
  }
  
  static function getTestClassNames($dir) {
    $arClassNames = array();
    foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $value) {
      if(
        strpos($value,'Test.php') && 
        ( strlen($value) - strpos($value,'Test.php') == 8)
      ) {
        require_once($value);
        $arClassNames[] = substr(basename($value),0,-4);
      }
    }
    return $arClassNames;
  }
}
?>